package com.xnyzc.lhy.order.mq.consumer;

import com.alibaba.fastjson.JSON;
import com.xnyzc.lhy.common.component.config.security.RocketConfig;
import com.xnyzc.lhy.common.component.redis.RedisCommon;
import com.xnyzc.lhy.common.constant.MqConstant;
import com.xnyzc.lhy.common.constant.MqConsumerGroupConstant;
import com.xnyzc.lhy.common.constant.RedisPrefixConstant;
import com.xnyzc.lhy.common.entity.Qw;
import com.xnyzc.lhy.common.util.CheckUtil;
import com.xnyzc.lhy.common.util.IDUtil;
import com.xnyzc.lhy.mis.entity.cms.config.OaSysSchedulingStrategy;
import com.xnyzc.lhy.order.entity.gps.OaDVehicleGps;
import com.xnyzc.lhy.order.entity.param.order.OrderParam;
import com.xnyzc.lhy.order.entity.user.OaDUserInfo;
import com.xnyzc.lhy.order.mapper.system.OaSysOrderDispatchRecordMapper;
import com.xnyzc.lhy.order.mapper.system.OaSysOrderDriverDispatchHistoryMapper;
import com.xnyzc.lhy.order.mapper.system.OaSysSchedulingStrategyMapper;
import com.xnyzc.lhy.order.mapper.user.OaDUserInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.geo.Point;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;

@Slf4j
@Component
public class MqGenerateOrderListConsumer {

    private DefaultMQPushConsumer consumer;

    @Autowired
    RocketConfig config;

    @Autowired
    RedisCommon redisCommon;

    @Value("${rocketMq.isStart}")
    private boolean isStart;

    @Autowired
    OaSysSchedulingStrategyMapper oaSysSchedulingStrategyMapper;


    @Autowired
    OaDUserInfoMapper userInfoMapper;

    /**
     * 订单调度记录表
     */
    @Autowired
    OaSysOrderDispatchRecordMapper oaSysOrderDispatchRecordMapper;

    /**
     * 订单调度司机历史表
     */
    @Autowired
    OaSysOrderDriverDispatchHistoryMapper oaSysOrderDriverDispatchHistoryMapper;

    /**
     * 开启监听
     */
    @PostConstruct
    public void init() {
        try {
            if (!isStart) {
                return;
            }
            consumer = new DefaultMQPushConsumer(MqConsumerGroupConstant.GENERATE_ORDER);
            consumer.setNamesrvAddr(config.getNameServerAddr());
            consumer.subscribe(config.getTopic(), MqConstant.DIDI_GENERATE_ORDER_LIST);
            consumer.setConsumeMessageBatchMaxSize(1);
            consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
            consumer.registerMessageListener(new MessageListenerConcurrently() {
                @Override
                public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                    MessageExt messageExt = msgs.get(0);
                    return MqGenerateOrderListConsumer.this.dealBody(messageExt);
                }
            });
            consumer.start();
            log.info("---------司机位置同步消费者启动完成-----o(*^▽^*)┛-------");
        } catch (Exception e) {
            log.info("---------司机位置同步消费者初始化失败----(# ﾟДﾟ)--------");
        }
    }


    /**
     * 处理业务逻辑
     *
     * @param messageExt
     * @return
     */
    public ConsumeConcurrentlyStatus dealBody(MessageExt messageExt) {
        OrderParam param = null;
        try {
            //发送的消息
            String body = new String(messageExt.getBody());
            if (CheckUtil.strIsEmpty(body)) {
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
            param = JSON.parseObject(body, OrderParam.class);
            if (CheckUtil.objIsNotEmpty(param)) {
                log.info("ORDER_HISTORY 预估价ID:[{}] 开始找车,找车参数:[{}]", param.getEstimateId(), param);
                List<OaDVehicleGps> vehicle = findVehicle(param);
                log.info("ORDER_HISTORY 预估价ID:[{}] 存入redis中的数据个数: {}", param.getEstimateId(), vehicle.size());
                if (vehicle.size() > 0) {
                    //存入Redis中
                    String key = RedisPrefixConstant.ORDER_DRIVER_LIST + param.getEstimateId();
                    redisCommon.set(key, JSON.toJSONString(vehicle));
                    redisCommon.expire(key, 60 * 2);
                }
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }

    /**
     * 查找车辆逻辑方法
     *
     * @return 返回在线车辆
     */
    public List<OaDVehicleGps> findVehicle(OrderParam pOrder) {
        List<OaDVehicleGps> result = new ArrayList<>();
        HashMap<String, Point> map = new HashMap<>();
        Qw qw = Qw.create();
        qw.select(OaDUserInfo.DRIVER_ID);
        qw.eq(OaDUserInfo.ACCEPTANC_ORDER_STATUS, 1).eq(OaDUserInfo.IS_ORDER, 0);
        List<OaDUserInfo> list = userInfoMapper.selectList(qw);
        log.info("ORDER_HISTORY 预估价ID:[{}] 查询到的未接单司机个数: {}", pOrder.getEstimateId(), list.size());
        for (OaDUserInfo oaDUserInfo : list) {
            // 司机轨迹前缀 + 司机ID
            String str = redisCommon.getStr(RedisPrefixConstant.GPS_VEH_KEY_PREFIX + oaDUserInfo.getDriverId());

            //判断是否有在线车辆
            if (CheckUtil.strIsNotEmpty(str)) {
                //获取司机轨迹
                OaDVehicleGps gps = JSON.parseObject(str, OaDVehicleGps.class);
                if (CheckUtil.objIsEmpty(gps)) {
                    continue;
                }
                //如果经纬度为空退出本次循环
                if (CheckUtil.strIsEmpty(gps.getLng()) || CheckUtil.strIsEmpty(gps.getLat())) {
                    continue;
                }
                Point point = new Point(Double.valueOf(gps.getLng()), Double.valueOf(gps.getLat()));
                map.put(String.valueOf(gps.getDriverId()), point);
                result.add(gps);
            }
        }
        log.info("ORDER_HISTORY 预估价ID:[{}] 获取到有轨迹并且未接单的司机个数: {}", pOrder.getEstimateId(), result.size());
        //进入里程筛选
        List<OaDVehicleGps> oaDVehicleGps = filterDriver(map, result, pOrder);
        log.info("ORDER_HISTORY 预估价ID:[{}] 存入redis中的数据个数: {}", pOrder.getEstimateId(), oaDVehicleGps.size());
        return oaDVehicleGps;
    }

    /**
     * redis直线筛选司机
     *
     * @param map
     * @param vehList
     * @param pOrder
     * @return
     */
    public List<OaDVehicleGps> filterDriver(HashMap<String, Point> map, List<OaDVehicleGps> vehList, OrderParam pOrder) {
        List<OaDVehicleGps> result = new ArrayList<>();
        if (map.size() <= 0) {
            result = new ArrayList<>();
            return result;
        }
        log.info("ORDER_HISTORY 预估价ID:[{}] 开始找车,进入司机里程筛选:[{}]", pOrder.getEstimateId());
        Qw qw = Qw.create();
        qw.eq(OaSysSchedulingStrategy.CITY_ID, pOrder.getCityId());
        qw.eq(OaSysSchedulingStrategy.STATE_FLAG, "ENABLED");
        List<OaSysSchedulingStrategy> oaSysSchedulingStrategys = oaSysSchedulingStrategyMapper.selectList(qw);
        //如果未获取到调度规则取消派单
        if (oaSysSchedulingStrategys.size() <= 0) {
            result = new ArrayList<>();
            return result;
        }
        OaSysSchedulingStrategy oaSysSchedulingStrategy = oaSysSchedulingStrategys.get(0);
        log.info("ORDER_HISTORY 预估价ID:[{}] 开始找车,获取的调度规则: [{}]", pOrder.getEstimateId(), oaSysSchedulingStrategy);
        String key = RedisPrefixConstant.DIRVER_GEO + IDUtil.nextId();
        redisCommon.addGeos(map, key);
        double maxDistance = oaSysSchedulingStrategy.getMaxDistance().doubleValue();

        log.info("0000000000000maxDistance00000:"+ maxDistance);

        Map<String, Object> stringObjectMap = redisCommon.geoRadius(maxDistance, Double.valueOf(pOrder.getFlng()), Double.valueOf(pOrder.getFlat()), key);
        log.info("ORDER_HISTORY 预估价ID:[{}] 开始找车,redis返回数据: [{}]", pOrder.getEstimateId(), stringObjectMap);
        if (stringObjectMap.containsKey("keys")) {
            List<String> keys = (ArrayList) stringObjectMap.get("keys");
            log.info("ORDER_HISTORY 预估价ID:[{}] 开始找车,筛选出符合里程要求的司机个数: [{}]", pOrder.getEstimateId(), keys.size());
            for (String s : keys) {
                for (OaDVehicleGps oaDVehicleGps : vehList) {
                    if (String.valueOf(oaDVehicleGps.getDriverId()).equals(s)) {
                        result.add(oaDVehicleGps);
                    }
                }
            }
        }
        String distance = "";
        if (stringObjectMap.containsKey("distance")) {
            distance = String.valueOf(stringObjectMap.get("distance"));
        }
        log.info("ORDER_HISTORY 预估价ID:[{}] 符合订单位置司机个数:{}, 当前订单起点: {},{} 平均距离起点: {}米, 删除量: {}", pOrder.getEstimateId(), result.size(), Double.valueOf(pOrder.getFlng()), Double.valueOf(pOrder.getFlat()), distance);
        return result;
    }
}
